﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using wscf.lightblue;
using System.Diagnostics;
using System.IO;

namespace wscf.console
{
	class Program
	{
		static void Main(string[] args)
		{
			try
			{
				Arguments CmdLine = new Arguments(args);

				bool showUsage = false;
				bool.TryParse(CmdLine["?"], out showUsage);
				if (showUsage)
				{
					ShowUsage();
					return;
				}

				string metadata = CmdLine[new string[] { "metadata", "m" }];
				if (metadata == null)
				{
					Error("Argument /metadata must be specified!");
					return;
				}

				string outputFile = CmdLine[new string[] { "out", "o" }];

				string rawLanguage = CmdLine[new string[] { "language", "l" }];
				ClrLanguage language = ClrLanguage.cs;
				if (rawLanguage != null)
				{
					switch (rawLanguage)
					{
						case "c#":
						case "cs":
						case "csharp":
							language = ClrLanguage.cs;
							break;
						case "vb":
						case "visualbasic":
							language = ClrLanguage.vb;
							break;
						case "c++":
						case "cpp":
							language = ClrLanguage.cpp;
							break;
					}
				}

				Dictionary<string, string> xmlNamespaceMappings = new Dictionary<string, string>();
				string rawNamespaceMappings = CmdLine[new string[] { "namespaceMappings", "n" }];
				if (rawNamespaceMappings != null)
				{
					string[] mappings = rawNamespaceMappings.Split(';');
					if (mappings != null)
					{
						foreach (string s in mappings)
						{
							string[] mapping = s.Split(',');
							if (mappings != null && mapping.Length > 1)
							{
								xmlNamespaceMappings.Add(mapping[0], mapping[1]);
							}
						}
					}
				}
				else
				{
					if (File.Exists(metadata) && Path.GetExtension(metadata).ToLower() == ".wsdl")
					{
						xmlNamespaceMappings.Add("*", CodeGenerator.GetWsdlTargetNamespace(metadata).Replace("http://", "").Replace('/', '.'));
					}
				}

				string rawReferencedAssemblies = CmdLine[new string[] { "referencedAssemblies", "r" }];
				List<string> referencedAssemblies = null;
				if (rawReferencedAssemblies != null)
				{
					referencedAssemblies = new List<string>(rawReferencedAssemblies.Split(','));
				}

				bool dataContractsOnly = false;
				bool.TryParse(CmdLine[new string[] { "dataContractsOnly", "dconly" }], out dataContractsOnly);

				bool dataContractSerializer = false;
				bool.TryParse(CmdLine[new string[] { "dataContractSerializer", "dcser" }], out dataContractSerializer);

				bool expandSchemas = false;
				bool.TryParse(CmdLine[new string[] { "expandSchemas", "exp" }], out expandSchemas);

				string configurationFile = CmdLine[new string[] { "config", "c" }];

				CodeGenerator.GenerateCode(metadata, outputFile, language, xmlNamespaceMappings,
					referencedAssemblies, dataContractsOnly, configurationFile, dataContractSerializer);

				Console.Out.WriteLine("Code generated successfully.");
			}
			catch (Exception exc)
			{
				Error(exc.ToString());
			}
		}

		static void Error(string message)
		{
			Console.Out.WriteLine(message);
			Console.Out.WriteLine();

			Environment.Exit(1);
		}

		static private void ShowUsage()
		{
			Console.Out.WriteLine("Web Service Contract First Code Generation Tool");
			Console.Out.WriteLine(@"Usage: wscf /m:MyService.wsdl [/exp] [/o:MyService.cs] [/l:cs] [/n:*,MyNamespace] [/r:a.dll,b.dll] [/dconly] 

/metadata (/m): The path to a metadata document (wsdl or xsd) that contains the contract to import into code (.wsdl, .xsd, .wspolicy or .wsmex).
You don't have to specify imported schemas.
You can use wildcards (*.xsd, *.wsdl) for this argument.
You can specify a semicolon-separated list of files.

/out (/o): Specifies the file name for the generated code.
Default: Derived from the WSDL definition name, WSDL service name or target namespace of one of the schemas.

/language (/l): Specifies the programming language to use for code generation. 
You should provide either a language name registered in the Machine.config file, or the fully-qualified name of a class that inherits from CodeDomProvider.
Values: c#, cs, csharp, vb, visualbasic, c++, cpp. Default: csharp.

/namespaceMappings (/n): Specifies a mapping from WSDL or XML Schema targetNamespaces to CLR namespaces. Form: <xmlns>,<clrns>[;<xmlns>,<clrns>]
Using '*' for the targetNamespace maps all targetNamespaces without an explicit mapping to that CLR namespace. 
To make sure that the message contract name does not collide with operation name, you should either qualify the type reference with ::, or make sure the names are unique. 
Default: Derived from the target namespace of the schema document for Data Contracts. 
The default namespace is used for all other generated types.

/referencedAssemblies (/r): References types in the specified assemblies. Form: <dll>[,<dll>]
When generating clients, use this option to specify assemblies that might contain types that represent the metadata being imported.
You cannot specify message contracts and XmlSerializer types using this switch.
If DateTimeOffset referenced, this type is used instead of generating a new type. 
If the application is written using .NET Framework 3.5, SvcUtil.exe references DateTimeOffset automatically.

/dataContractsOnly (/dconly): Generates code for data contract types only. Service Contract types are not generated. 
You should only specify local metadata files for this option.

/config (/c): Create new WCF web server configuration file or mere  with existing.");
		}

	}
}
